#include <QtGui>

#include "finddialog.h"
#include "gotocelldialog.h"
#include "mainwindow.h"
#include "sortdialog.h"
#include "spreadsheet.h"

MainWindow::MainWindow(){
	spreadsheet = new Spreadsheet;
	setCentralWidget(spreadsheet);

	createActions();
	createMenus();
	createContextMenu();
	createToolBars();
	createStatusBar();

	readSettings();

	findDialog = 0;

	setWindowIcon(QIcon(":/images/icon.png"));
	setCurrentFile("");
}

void MainWindow::closeEvent(QCloseEvent *event){
	if(okToContinue()){
		writeSettings();
		event->accept();
	}
	else{
		event->ignore();
	}
}

void MainWindow::newFile(){
	if(okToContinue()){
		spreadsheet->clear();
		setCurrentFile("");
	}
}

void MainWindow::open(){
	if(okToContinue()){
		QString fileName = QFileDialog::getOpenFileName(this,
				tr("Open Spreadsheet"), ".",
				tr("Spreadsheet files (*.sp)"));
		if(!fileName.isEmpty())
			loadFile(fileName);
	}
}

bool MainWindow::save(){
	if(curFile.isEmpty()){
		return saveAs();
	}
	else{
		return saveFile(curFile);
	}
}

bool MainWindow::saveAs(){
	QString fileName = QFileDialog::getSaveFileName(this,
			tr("Save Spreadsheet"), ".",
			tr("Spreadsheet files (*.sp)"));
	if(fileName.isEmpty())
		return false;
	return saveFile(fileName);
}

void MainWindow::find(){
	if(!findDialog){
		findDialog = new FindDialog(this);
		connect(findDialog, SIGNAL(findNext(const QString &,
						Qt::CaseSensitivity)),
				spreadsheet, SLOT(findNext(const QString &,
						Qt::CaseSensitivity)));
		connect(findDialog, SIGNAL(findPrev(const QString &,
						Qt::CaseSensitivity)),
				spreadsheet, SLOT(findPrev(const QString &,
						Qt::CaseSensitivity)));
		findDialog->show();
		findDialog->raise();
		findDialog->activateWindow();
	}
}

void MainWindow::goToCell(){
	GoToCellDialog dialog(this);
	if(dialog.exec()){
		QString str = dialog.lineEdit->text().toUpper();
		spreadsheet->setCurrentCell(str.mid(1).toInt() - 1,
				str[0].unicode() - 'A');
	}
}

void MainWindow::sort(){
	SortDialog dialog(this);
	QTableWidgetSelectRange range = spreadsheet->selectedRange();
	dialog.setColumnRange('A' + range.leftColumn(),
			'A' + range.rightColumn());
	if(dialog.exec()){
		SpreadsheetCompare compare;
		compare.keys[0] = 
			dialog.primaryColumnCombo->currentIndex();
		compare.keys[1] =
			dialog.secondaryColumnCombo->currentIndex() - 1;
		compare.keys[2] =
			dialog.tertiaryColumnCombo->currentIndex() - 1;
		compare.ascending[0] = 
			(dialog.primaryOrderCombo->currentIndex() == 0);
		compare.ascending[1] = 
			(dialog.secondaryOrderCombo->currentIndex() == 0);
		compare.ascending[2] =
			(dialog.tertiaryOrderCombo->currentIndex() == 0);
		spreadsheet->sort(compare);
	}
}

void MainWindow::about(){
	QMessageBox::about(this, tr("About Spreadsheet"),
			tr("<h2>Spreadsheet 1.1</h2>"
				"<p>Copyright &copy; 2018 Software Inc."
				"<p>Spreadsheet is a small application that "
				"demostrates QAction, QMainWindow, QMenuBar, "
				"QStatusBar, QTableWidget, QToolBar, and many other "
				"Qt classes."));
}

void MainWindow::openRecentFile(){
	if(okToContinue()){
		QAction *action = qobject_case<QAction*>(sender());
		if(action)
			loadFile(action->data().toString());
	}
}

void MainWindow::updateStatusBar(){
	locationLabel->setText(spreadsheet->currentLocation());
	formulaLabel->setText(spreadsheet->currentFormula());
}

void MainWindow::spreadsheetModified(){
	setWindowModified(true);
	updateStatusBar();
}


void MainWindow::createActions(){
	newAction = new QAction(tr("&New"), this);
	newAction->setIcon(QIcon(":/images/new.png"));
	newAction->setShortcut(QKeySequence::New);
	newAction->setStatusTip(tr("Create a new spreadsheet file"));
	connect(newAction, SIGNAL(triggered()),
			this, SLOT(newFile()));

	openAction = new QAction(tr("&Open"), this);
	openAction->setIcon(QIcon(":/images/open.png"));
	openAction->setShortcut(QKeySequence::Open);
	openAction->setStatusTip(tr("Open an existing spreadsheet file"));
	connect(openAction, SIGNAL(triggered()),
			this, SLOT(open()));

	saveAction = new QAction(tr("&Save"), this);
	saveAction->setIcon(QIcon(":/images/save.png"));
	saveAction->setShortcut(QKeySequence::Save);
	saveAction->setStatusTip(tr("Save current spreadsheet file"));
	connect(saveAction, SIGNAL(triggered()),
			this, SLOT(save()));

	saveAsAction = new QAction(tr("Save &As"), this);
	connect(saveAsAction, SIGNAL(triggered()),
			this, SLOT(saveAs()));

	for(int i = 0 ; i < MaxRecentFiles; i++){
		recentFileActions[i] = new QAction(this);
		recentFileActions[i]->setVisiable(false);
		connect(recentFileActions[i], SIGNAL(triggered()),
				this, SLOT(openRecentFile()));
	}

	exitAction = new QAction(tr("E&xit"), this);
	exitAction->setShortcut(tr("Ctrl+Q"));
	exitAction->setStatusTip(tr("Exit the application"));
	connect(exitAction, SIGNAL(triggered()),
			this, SLOT(close()));

	//...
	selectAllAction = new QAction(tr("&All"), this);
	selectAllAction->setShortcut(QKeySequence::SelectAll);
	selectAllAction->setStatusTip(tr("Select all the cell in the"
				" spreadsheet"));
	connect(selectAllAction, SIGNAL(triggered()),
			spreadsheet, SLOT(selectAll()));

	//...
	showGridAction = new QAction(tr("&Show Grid"), this);
	showGridAction->setCheckable(true);
	showGridAction->setCheckable(spreadsheet->showGrid());
	showGridAction->setStatusTip(tr("Show or hide the spreadsheet's "
				"grid"));
	connect(showGridAction, SIGNAL(toggled(bool)),
			spreadsheet, SLOT(setShowGrid(bool)));
	
	//...
	aboutQtAction = new QAction(tr("About &Qt"), this);
	aboutQtAction->setStatusTip(tr("Show the Qt library's About box"));
	connect(aboutQtAction, SIGNAL(triggered()),
			qApp, SLOT(aboutQt()));
}

void MainWindow::createMenus(){
	fileMenu = menuBar()->addMenu(tr("&File"));
	fileMenu->addAction(newAction);
	fileMenu->addAction(openAction);
	fileMenu->addAction(saveAction);
	fileMenu->addAction(saveAsAction);
	separatorAction = fileMenu->addSeparator();
	for(int i = 0 ; i < MaxRecentFiles; i++){
		fileMenu->addAction(recentFileActions[i]);
	}
	fileMenu->addSeparator();
	fileMenu->addAction(exitAction);

	editMenu = menuBar()->addMenu(tr("&Edit"));
	editMenu->addAction(cutAction);
	editMenu->addAction(copyAction);
	editMenu->addAction(pasteAction);
	editMenu->addAction(deleteAction);

	selectSubMenu = editMenu->addMenu(tr("&Select"));
	selectSubMenu->addAction(selectRowAction);
	selectSubMenu->addAction(selectColumnAction);
	selectSubMenu->addAction(selectAllAction);
	
	editMenu->addSeparator();
	editMenu->addAction(findAction);
	editMenu->addAction(goToCellAction);

	toolsMenu = menuBar()->addMenu(tr("&Tools"));
	toolsMenu->addAction(recalculateAction);
	toolsMenu->addAction(sortAction);

	optionsMenu = menuBar()->addMenu(tr("&Options"));
	optionsMenu->addAction(showGridAction);
	optionsMenu->addAction(autoRecalculateAction);

	menuBar()->addSeparator();

	helpMenu = menuBar()->addMenu(tr("&Help"));
	helpMenu->addAction(aboutAction);
	helpMenu->addAction(aboutQtAction);
}

void MainWindow::createContextMenu(){
	spreadsheet->addAction(cutAction);
	spreadsheet->addAction(copyAction);
	spreadsheet->addAction(pasteAction);
	spreadsheet->setContextMenuPolicy(Qt::ActionContextMenu);
}

void MainWindow::createToolBars(){
	fileToolBar = addToolBar(tr("&File"));
	fileToolBar->addAction(newAction);
	fileToolBar->addAction(openAction);
	fileToolBar->addAction(saveAction);

	editToolBar = addToolBar(tr("&Edit"));
	editToolBar->addAction(cutAction);
	editToolBar->addAction(copyAction);
	editToolBar->addAction(pasteAction);
	editToolBar->addSeparator();
	editToolBar->addAction(findAction);
	editToolBar->addAction(goToCellAction);
}

void MainWindow::createStatusBar(){
	locationLabel = new QLabel(" W999 ");
	locationLabel->setAlignment(Qt::AlignHCenter);
	locationLabel->setMinimumSize(locationLabel->sizeHint());

	formulaLabel = new QLabel;
	formulaLabel->setIndent(3);

	statusBar()->addWidget(locationLabel);
	statusBar()->addWidget(formulaLabel);

	connect(spreadsheet, SIGNAL(currentCellChanged(int, int, int, int)),
			this, SLOT(updateStatusBar()));
	connect(spreadsheet, SIGNAL(modified()),
			this, SLOT(spreadsheetModified()));

	updateStatusBar();
}

void MainWindow::writeSettings(){
	QSettings settings("Software Inc.", "Spreadsheet");
	settings.setValue("geometry", saveGeometry());
	settings.setValue("recentFiles", recentFiles);
	settings.setValue("showGrid", showGridAction->isChecked());
	settings.setValue("autoRecalc", autoRecalculateAction->isChecked());
}

void MainWindow::readSettings(){
	QSettings settings("Software Inc.", "Spreadsheet");
	restoreGeometry(settings.value("geometry").toByteArray());

	recentFiles = settings.value("recentFiles").toStringList();
	updateRecentFileActions();

	bool showGrid = setting.value("showGrid", true).toBool();
	showGridAction->setChecked(showGrid);

	bool autoRecalc = settings.value("autoRecalc", true).toBool();
	autoRecalculateAction->setChecked(autoRecalc);
}

bool MainWindow::okToContinue(){
	if(isWindowModified()){
		int r = QMessageBox::warning(this, tr("Spreadsheet"),
				tr("The document has been modified.\n"
					"Do you want to save your changes?"),
				QMessageBox::Yes | QMessageBox::No 
				| QMessageBox::Cancel);
		if(r == QMessageBox::Yes)
			return save();
		else if(r == QMessageBox::Cancel)
			return false;
	}
	return true;
}

bool MainWindow::loadFile(const QString &fileName){
	if(!Spreadsheet->readFile(fileName)){
		statusBar()->showMessage(tr("Loading canceled"), 2000);
		return false;
	}
	setCurrentFile(fileName);
	statusBar()->showMessage(tr("File loaded"), 2000);
	return true;
}

bool MainWindow::saveFile(const QString &fileName){
	if(!Spreadsheet->writeFile(fileName)){
		statusBar()->showMessage(tr("Saving canceled"), 2000);
		return false;
	}
}

void setCurrentFile(const QString &fileName){
	curFile = fileName;
	setWindowModified(false);
	
	QString shownName = tr("Untitled");
	if(!curFile.isEmpty()){
		shownName = strippedName(curFile);
		recentFiles.removeAll(curFile);
		recentFiles.prepend(curFile);
		updateRecentFileActions();
	}

	setWindowTitle(tr("%1[*] - %2").arg(shownName)
									.arg(tr("Spreadsheet")));
}

void updateRecentFileActions(){
	QMutableStringListIterator i(recentFiles);
	while(i.hasNext()){
		if(!QFile::exists(i.next()))
			i.remove();
	}
	for(int j = 0; j < MaxRecentFiles; j++){
		if(j < recentFiles.count()){
			QString text = tr("&%1 %2")
				.arg(j+1)
				.arg(strippedName(recentFiles[j]));
			recentFileActions[j]->setText(text);
			recentFileActions[j]->setData(recentFiles[j]);
			recentFileActions[j]->setVisiable(true);
		}
		else{
			recentFileActions[j]->setVisiable(false);
		}
	}
	separatorAction->setVisiable(!recentFile.isEmpty());
}

QString MainWindow::strippedName(const QString &fullFileName){
	return	QFileInfo(fullFileName).fileName();
}
